﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using Triangle;

namespace RectangleSearch
{
    class Program
    {
        private static int[] _iid = new int[6];
        private static readonly int[] IidFor = new int[6];
        private static readonly ulong[] RectangleList = new ulong[18];
        private static readonly Dictionary<string, long> countSquare = new Dictionary<string, long>();
        private static readonly Dictionary<string, long> sRectangle = new Dictionary<string, long>();
        const string FileStart = "start.ini";
        /// <summary>
        /// Тестовый рандом
        /// </summary>
        /// <param name="args"></param>
        private static Random _random = new Random();

        static void Main(string[] args)
        {
            if(!File.Exists(FileStart))
                return;
            // чтение конфигурационного файла
            var reader = new StreamReader(FileStart);
            string s;
            while((s = reader.ReadLine()) != null)
            {
                // line2=23 получение начальных данных(с какой картинки начинать)
                var regex = new Regex("line(\\d)\\=(\\d+)");
                var match = regex.Match(s);
                if (match.Groups.Count == 3)
                {
                    _iid[Convert.ToInt32(match.Groups[1].ToString())] = Convert.ToInt32(match.Groups[2].ToString());
                    continue;
                }

                // получение ранее сохраненных данных о количестве квадратиков
                regex = new Regex("countSquare(\\d+)\\=(\\d+)");
                match = regex.Match(s);
                if (match.Groups.Count > 1)
                {
                    if (countSquare.ContainsKey(match.Groups[1].ToString()))
                        countSquare[match.Groups[1].ToString()] = long.Parse(match.Groups[2].ToString());
                    else
                        countSquare.Add(match.Groups[1].ToString(), long.Parse(match.Groups[2].ToString()));
                    continue;
                }

                // получение ранее сохраненных данных о площади прямоугольника
                regex = new Regex("sRectangle(\\d+)=(\\d+)");
                match = regex.Match(s);

                if (match.Groups.Count > 1)
                {
                    if (sRectangle.ContainsKey(match.Groups[1].ToString()))
                        sRectangle[match.Groups[1].ToString()] = long.Parse(match.Groups[2].ToString());
                    else 
                        sRectangle.Add(match.Groups[1].ToString(), long.Parse(match.Groups[2].ToString()));
                    continue;
                }
            }
            reader.Close();

            // создание отдельного потока для логирования
            var backup = new Thread(Backup) {IsBackground = true};
            backup.Start();
            Console.WriteLine("Backup started. Starting algorithm");
            Start();
        }

        private static void Start()
        {
            // перебор всех кортинок начиная со стартовой позиции
            for (IidFor[0] = _iid[0]; IidFor[0] < 128; ++IidFor[0])
            {
                for (IidFor[1] = _iid[1]; IidFor[1] < 128; ++IidFor[1])
                {
                    for (IidFor[2] = _iid[2]; IidFor[2] < 128; ++IidFor[2])
                    {
                        for (IidFor[3] = _iid[3]; IidFor[3] < 128; ++IidFor[3])
                        {
                            for (IidFor[4] = _iid[4]; IidFor[4] < 128; ++IidFor[4])
                            {
                                for (IidFor[5] = _iid[5]; IidFor[5] < 128; ++IidFor[5])
                                {
                                    var countTreangle = TriangleSearch();
                                    RectangleList[countTreangle]++;
                                }
                                _iid[5] = 0;
                            }
                            _iid[4] = 0;
                        }
                        _iid[3] = 0;
                        Console.WriteLine("Прошла одна итерация в третьем цикле");
                    }
                    _iid[2] = 0;
                }
                _iid[1] = 0;
            }
        }

        /// <summary>
        /// логирование полученных результатов
        /// </summary>
        private static void Backup()
        {
            while (true)
            {
                // каждые 15 минут сохраняем данные
                Thread.Sleep(15 * 60 * 1000);
                
                var writer = new StreamWriter(FileStart, true);
                // сохранение текущей позиции
                lock(IidFor)
                {
                    for (var i = 0; i < 6; i++)
                        writer.WriteLine("line{0}={1}", i, IidFor[i]);
                }

                // сохранение количества квадратиков
                lock (countSquare)
                {
                    var keys = new string[countSquare.Keys.Count];
                    countSquare.Keys.CopyTo(keys, 0);
                    for (var i = 0; i < keys.Count(); i++)
                        writer.WriteLine("countSquare{0}={1}", keys[i], countSquare[keys[i]]);
                }

                // сохранение площадей прямоугольников
                lock (sRectangle)
                {
                    var keys = new string[sRectangle.Keys.Count];
                    sRectangle.Keys.CopyTo(keys, 0);
                    for (var i = 0; i < keys.Count(); i++)
                        writer.WriteLine("sRectangle{0}={1}", keys[i], sRectangle[keys[i]]);
                }

                writer.Close();
            }
        }

        /// <summary>
        /// поиск прямоугольников
        /// </summary>
        /// <returns>сколько прямоугольников нашлось и какого типа</returns>
        private static int TriangleSearch()
        {
            var id = IidFor;

            new Map(new[]
                        {
                            new[] {id[0] % 2, id[1] % 2, id[2] % 2, id[3] % 2, id[4] % 2, id[5] % 2},
                            new[] {(id[0] / 2) % 2, (id[1] / 2) % 2, (id[2] / 2) % 2, (id[3] / 2) % 2, (id[4] / 2) % 2, (id[5] / 2) % 2},
                            new[] {(id[0] / 4) % 2, (id[1] / 4) % 2, (id[2] / 4) % 2, (id[3] / 4) % 2, (id[4] / 4) % 2, (id[5] / 4) % 2},
                            new[] {(id[0] / 8) % 2, (id[1] / 8) % 2, (id[2] / 8) % 2, (id[3] / 8) % 2, (id[4] / 8) % 2, (id[5] / 8) % 2},
                            new[] {(id[0] / 16) % 2, (id[1] / 16) % 2, (id[2] / 16) % 2, (id[3] / 16) % 2, (id[4] / 16) % 2, (id[5] / 16) % 2},
                            new[] {(id[0] / 32) % 2, (id[1] / 32) % 2, (id[2] / 32) % 2, (id[3] / 32) % 2, (id[4] / 32) % 2, (id[5] / 32) % 2},
                            new[] {(id[0] / 64) % 2, (id[1] / 64) % 2, (id[2] / 64) % 2, (id[3] / 64) % 2, (id[4] / 64) % 2, (id[5] / 64) % 2}
                        });
            Node goal;
            var pureCount = 0;
            var dirtyCount = 0;
            // поиск связных точек
            while ((goal = Map.Find()) != null)
            {
                var srch = new Search(goal);
                if (goal.GetNode(Map.GetValueNode(goal)).Count == 0)
                {
                    Map.Paint(new List<Node> { goal }, false);
                    continue;
                }
                srch.Dfs(goal.GetNode(Map.GetValueNode(goal))[0], goal);
                // получение количества прямоугольников
                var weight = srch.Stack.Count;

                Map.Paint(srch.Stack.ToList(), false);
                var cc = new ConnectedComponent(srch.Stack);
                var area = cc.IsTriangle(cc.GetCorner());
                // получение площади прямоугольника
                var iArea = (int) area;
                if (iArea != 0)
                {
                    if (countSquare.ContainsKey(weight.ToString()))
                        countSquare[weight.ToString()] = countSquare[weight.ToString()] + 1;
                    else
                        countSquare.Add(weight.ToString(), 1);

                    if (sRectangle.ContainsKey(iArea.ToString()))
                        sRectangle[iArea.ToString()] = sRectangle[iArea.ToString()] + 1;
                    else
                        sRectangle.Add(iArea.ToString(), 1);
                } else
                {
                    if (countSquare.ContainsKey("0"))
                        countSquare["0"] = countSquare["0"] + 1;
                    else
                        countSquare.Add("0", 1);

                    if (sRectangle.ContainsKey("0"))
                        sRectangle["0"] = sRectangle["0"] + 1;
                    else
                        sRectangle.Add("0", 1);
                }

                if (area != 0.0)
                    if (cc.IsPure)
                        pureCount++;
                    else
                        dirtyCount++;
            }
            return 0;
        }
    }
}
